package com.atguigu.tingshu.account.listener;

import com.atguigu.tingshu.account.service.UserAccountService;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.rabbit.constant.MqConst;
import com.atguigu.tingshu.model.account.UserAccount;
import com.rabbitmq.client.Channel;
import io.lettuce.core.dynamic.annotation.Key;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.io.IOException;

@Component
@Slf4j
public class UserAccountRegisterListener {

    @Autowired
    private UserAccountService userAccountService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    private Long count = 0L;


    @RabbitListener(bindings = @QueueBinding(
            exchange = @Exchange(value = MqConst.EXCHANGE_USER, durable = "true"),
            value = @Queue(value = MqConst.QUEUE_USER_REGISTER, durable = "true"),
            key = MqConst.ROUTING_USER_REGISTER)
    )
    @SneakyThrows
    public void register(String constant, Message message, Channel channel) {
        long deliveryTag = message.getMessageProperties().getDeliveryTag();
        if (!StringUtils.hasText(constant)) {
            log.error("网络异常 未收到消息内容");
            return;
        }
        // 给用户注册账户信息
        // 新建一个用户对象
        UserAccount userAccount = new UserAccount();
        userAccount.setUserId(Long.parseLong(constant));
        try {
            userAccountService.saveAccount(userAccount);// 如果未发生异常 则ack 若此处发生异常 则尝试重新入队消费 次数为三次
            channel.basicAck(deliveryTag, false);// 若在此处发生异常 则说明消息业务已经执行 但未能成功确认消息 需要手动确认
        } catch (IOException e) {
            channel.basicNack(deliveryTag, false, false);// 手动将消息丢掉
            log.error("网络异常{}", e.getMessage());
        } catch (GuiguException e) {
            // 如果来到此处 说明业务 执行失败 尝试重新入队消费
            // MD5防重一下
            String entry = "register_count_" + constant;
            count = redisTemplate.opsForValue().increment(entry);
            if (count >= 3) {
                redisTemplate.delete(entry);
                channel.basicNack(deliveryTag, false, false);
                log.error("服务端异常,用户id:{}", constant);
            } else {
                channel.basicNack(deliveryTag, false, true);// 重新入队
                log.info("用户id:{} 重新入队,次数为{}次", constant, count);
            }
        }
    }
}
